/***************************************************************************
 *                                                                         *
 * Copyright (c) 2007 - 2009 Nuvoton Technology Corp. All rights reserved.*
 *                                                                         *
 ***************************************************************************/
 
#ifdef ECOS
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "drv_api.h"
#include "diag.h"
#include "wbio.h"
#include "NUC900_GE.h"
#include "NUC900_reg.h"
#else
#include <stdio.h>
#include "NUC900_GE.h"
#include "wbio.h"
#ifdef _NUC900_
#include "NUC900_reg.h"
#else
#include "reg702.h"
#endif
#endif

unsigned int GFX_BPP;
unsigned int GFX_WIDTH;
unsigned int GFX_HEIGHT;
unsigned int GFX_PITCH;
unsigned int GFX_SIZE;


__align(32) void *GFX_START_ADDR;
__align(32) void *MONO_SOURCE_ADDR;
__align(32) void *COLOR_SOURCE_ADDR;
__align(32) void *CMODEL_START_ADDR;
__align(32) void *GFX_OFFSCREEN_ADDR;
__align(32) void *GFX_PAT_ADDR;


void *Orig_GFX_START_ADDR;
void *Orig_MONO_SOURCE_ADDR;
void *Orig_COLOR_SOURCE_ADDR;
void *Orig_CMODEL_START_ADDR;
void *Orig_GFX_OFFSCREEN_ADDR;
void *Orig_GFX_PAT_ADDR;

void *_ScreenBufferPtr;
void *_MonoSrcBufferPtr, *_ColorSrcBufferPtr;
void *_HostBackBufferPtr;

/* For align 32 */
unsigned int shift_pointer(int ptr, int align)   
{
	unsigned int pos;
	int remain;
	pos = ptr;
	//printf("pointer position is %x\n",ptr);
	if( (ptr%align)!=0)
	{
		remain = ptr % align;
		ptr = ptr + (align - remain);
		return ptr;
	}
	else
		return pos;
}
///////////////////////////////////////////////////////////////////////////////
//
// Function: init_GE()
//
// Description:
//   Graphics engine initialization. 
//   parameter : set bit per pixel, width and height of diplay memory
///////////////////////////////////////////////////////////////////////////////
//void init_GE(void)
void init_GE(int bpp, int width, int height, void *destination)
{
  UINT32 data32;
  
  GFX_BPP = bpp;
  GFX_WIDTH = width;
  GFX_HEIGHT = height;
  GFX_PITCH = (GFX_WIDTH*(GFX_BPP/8));
  GFX_SIZE = (GFX_HEIGHT*GFX_PITCH);
  
  //Orig_GFX_START_ADDR = GFX_START_ADDR = (void *)malloc(GFX_SIZE+65536);
  if(destination == NULL) {
  	Orig_GFX_START_ADDR = GFX_START_ADDR = (void *)vpostGetFrameBuffer();
  	//GFX_START_ADDR = (void *)shift_pointer((int)GFX_START_ADDR, 65536);
  } else {
  	Orig_GFX_START_ADDR = GFX_START_ADDR = (void *)destination;
  }
  
  Orig_GFX_PAT_ADDR = GFX_PAT_ADDR = (void *)malloc((8*8*(GFX_BPP/8))*2);
  GFX_PAT_ADDR = (void *)shift_pointer((int)GFX_PAT_ADDR, (8*8*(GFX_BPP/8))*2);  // two times of boundary size
  
  Orig_MONO_SOURCE_ADDR = MONO_SOURCE_ADDR = (void *)malloc(GFX_SIZE+32);
  MONO_SOURCE_ADDR = (void *)shift_pointer((int)MONO_SOURCE_ADDR, 32);
  Orig_COLOR_SOURCE_ADDR = COLOR_SOURCE_ADDR = (void *)malloc(GFX_SIZE+32);
  COLOR_SOURCE_ADDR = (void *)shift_pointer((int)COLOR_SOURCE_ADDR, 32);
  Orig_CMODEL_START_ADDR = CMODEL_START_ADDR = (void *)malloc(GFX_SIZE+32);
  CMODEL_START_ADDR = (void *)shift_pointer((int)CMODEL_START_ADDR, 32);
  Orig_GFX_OFFSCREEN_ADDR = GFX_OFFSCREEN_ADDR = (void *)malloc(GFX_SIZE+32);
  GFX_OFFSCREEN_ADDR = (void *)shift_pointer((int)GFX_OFFSCREEN_ADDR, 32);
  
  #ifdef DEBUG
  printf("init_GE()\n");
  printf("screen width = %d\n", GFX_WIDTH);
  printf("screen height = %d\n", GFX_HEIGHT);
  printf("screen bpp = %d\n", GFX_BPP);
  printf("screen size = 0x%x\n", GFX_SIZE);
  #endif  
  
//#ifdef GE_RESET
  /*--- reset graphics engine (undocumented) ---*/
  //reset_GE();
//#endif  
  
  *((unsigned volatile int *) 0xB0000200) |= 0x400; //enable 2D clock
  
  outpw(REG_2D_GEINTS, 0); // clear interrupt
  outpw(REG_2D_GEPLS, (int)GFX_PAT_ADDR);
  outpw(REG_2D_GEC, 0); // disable interrupt
  outpw(REG_2D_GEXYDORG, (int)GFX_START_ADDR);
  outpw(REG_2D_GEXYSORG, (int)GFX_START_ADDR);

  outpw(REG_2D_GEWPM, 0x00ffffff); // write plane mask
  
  data32 = GE_BPP_8; // default is 8 bpp 

  if (GFX_BPP==16)
  {
    data32 |= GE_BPP_16;
  }
  else if (GFX_BPP==32)
  {
    data32 |= GE_BPP_32;
  }
  
  outpw(REG_2D_GEMC, data32);
#if 0  
  //
  // avoid V3 FPGA bug (fixed)
  //
  outpw(REG_2D_GEMC, data32 | 0x01010000);
#endif

  _ScreenBufferPtr = (void *)GFX_START_ADDR; 
  _MonoSrcBufferPtr = (void *)MONO_SOURCE_ADDR;
  _ColorSrcBufferPtr = (void *)COLOR_SOURCE_ADDR;
  //_HostBackBufferPtr = (void *)((int)COLOR_SOURCE_ADDR+1024);

}

void reset_GE()
{
  UINT32 temp32;

  /*
  ** b6: FIFO reset
  ** b7: Engine reset
  */
#if 1
  //   
  // 2004-07-23:
  // Change the reset sequence according to the suggestion from designer.
  // If FIFO reset and Engine reset are enabled at the same time, FIFO 
  // reset may be ignored.
  //
  outpw(REG_2D_GEMC, 0x40); // FIFO reset
  outpw(REG_2D_GEMC, 0x00);
    
  outpw(REG_2D_GEMC, 0x80); // Engine reset
  outpw(REG_2D_GEMC, 0x00);
  
#else  
  temp32 = inpw(REG_2D_GEMC);
  temp32 |= 0x000000c0;
  outpw(REG_2D_GEMC, temp32);
  temp32 &= 0xffffff3f;
  outpw(REG_2D_GEMC, temp32);
#endif    


  //memset((int)GFX_START_ADDR,0,GFX_SIZE);  // clear display memory
  free(Orig_GFX_START_ADDR);
  free(Orig_COLOR_SOURCE_ADDR);
  free(Orig_CMODEL_START_ADDR);
  free(Orig_GFX_OFFSCREEN_ADDR);
  free(Orig_GFX_PAT_ADDR);
  free(Orig_MONO_SOURCE_ADDR);
  
}


void reset_GE_FIFO()
{
  UINT32 temp32;
  
  /*
  ** b6: FIFO reset
  ** b7: Engine reset
  */
  temp32 = inpw(REG_2D_GEMC);
  temp32 |= 0x00000040;
  outpw(REG_2D_GEMC, temp32);
  temp32 &= 0xffffffbf;
  outpw(REG_2D_GEMC, temp32);
}
